#pragma once

#include <cstddef>

/**
 * @brief 第五版本：实现 reset 功能。
 *
 * reset 允许外部：
 *   - 释放当前资源（不传参）
 *   - 释放当前资源并接管新的裸指针
 *
 * 注意：
 *   - 在 reset 中调用删除器时需先判断当前指针是否为空。
 */
template <typename T, typename Deleter = void(*)(T*)>
class UniquePtr {
public:
    using pointer      = T*;
    using element_type = T;
    using deleter_type = Deleter;

    static void default_delete(T* ptr) noexcept {
        delete ptr;
    }

    constexpr UniquePtr() noexcept
        : ptr_(nullptr)
        , deleter_(default_delete) {}

    constexpr UniquePtr(std::nullptr_t) noexcept
        : UniquePtr() {}

    explicit UniquePtr(pointer ptr) noexcept
        : ptr_(ptr)
        , deleter_(default_delete) {}

    ~UniquePtr() {
        reset(); // 析构时复用 reset 逻辑
    }

    /**
     * @brief 释放当前资源，并可选择性接管新指针。
     *
     * @param ptr 新指针（默认值为 nullptr）。
     *            传入新指针时，相当于“重置”到新的资源。
     */
    void reset(pointer ptr = nullptr) noexcept {
        if (ptr_) {             // 仅当当前确实持有资源时才调用删除器
            deleter_(ptr_);
        }
        ptr_ = ptr;             // 更新托管指针
    }

    pointer get() const noexcept {
        return ptr_;
    }

    element_type& operator*() const noexcept {
        return *ptr_;
    }

    pointer operator->() const noexcept {
        return ptr_;
    }

    explicit operator bool() const noexcept {
        return ptr_ != nullptr;
    }

private:
    pointer      ptr_;
    deleter_type deleter_;
};